package com.bkck.sharkblockade.levels.item;

import java.util.List;
import com.bkck.sharkblockade.fish.Fish;
import com.bkck.sharkblockade.levels.paddle.Paddle;
import com.bkck.sharkblockade.levels.ball.Ball;
import com.bkck.sharkblockade.levels.block.BlockEdges;
import com.bkck.sharkblockade.levels.harpoon.Harpoon;
import com.bkck.sharkblockade.levels.shark.Shark;
import com.bkck.sharkblockade.levels.thread.MainGamePanel;
import com.bkck.sharkblockade.levels.thread.MainThread;
import android.graphics.Bitmap;
import android.graphics.Canvas;

/**
 * Item class for power ups and power downs
 * 
 * @author Team BKCK
 */
public class Item {

  // more power up and down to add later
  public final static int LARGER_PADDLE = 0;
  public final static int SMALLER_PADDLE = 1;
  public final static int FASTER_BALL = 2;
  public final static int SLOWER_BALL = 3;
  public final static int HARPOON = 4;
  public final static int FASTER_SHARK = 5;
  public final static int SLOWER_SHARK = 6;
  public final static int SPIKED_BALL = 7;
  public final static int GHOST_BALL = 8;
  public final static int BOMB = 9;

  // the falling speed
  private float pixelsPerMeter = 5;

  // the item image
  private Bitmap bitmap;

  // the item type
  private Integer type;

  // the item coordinate
  private float x;
  private float y;

  // the item falling speed
  private float yVelocity;

  // the item dimension
  private int width;
  private int height;

  // time remaining to for the item effect.
  private long timeRemaining = -1;

  // used to update position during each frame.
  private long lastUpdateTime = -1;

  // whether the item is falling.
  private boolean visible;

  // frame duration in milliseconds
  private int frameDuration = 200;

  private long elapsedTime = 0;

  /**
   * The constructor.
   * 
   * @param bitmap The item image.
   */
  public Item(Bitmap bitmap) {
    this.bitmap = bitmap;
    // apear on random x coordinate
    this.x = (float) (Math.random() * (MainGamePanel.viewWidth - width));
    // fall from above the screen.

    // make it on outside the top of the screen before falling
    this.y = -50;
    this.yVelocity = 0;

    // item type (CHANGED)
    this.type = null;

    // dimension
    this.width = bitmap.getWidth();
    this.height = bitmap.getHeight();

    // hiding on the top
    this.visible = false;
  }

  /**
   * Empty constructor to be called by Activities.
   */
  public Item() {

  }

  /**
   * Return whether this item is visible to the player.
   * 
   * @return
   */
  public boolean isVisible() {
    return visible;
  }

  /**
   * Set visibility for the item.
   * 
   * @param visible
   */
  public void setVisible(boolean visible) {
    this.visible = visible;
  }

  /**
   * Return the last update time.
   * 
   * @return The last update time.
   */
  public long getLastUpdateTime() {
    return lastUpdateTime;
  }

  /**
   * Set the last update time.
   * 
   * @param lastUpdateTime
   */
  public void setLastUpdateTime(long lastUpdateTime) {
    this.lastUpdateTime = lastUpdateTime;
  }

  /**
   * Set the y velocity for the item.
   * 
   * @param yVelocity
   */
  public void setYVelocity(float yVelocity) {
    this.yVelocity = yVelocity;
  }

  /**
   * Return the y velocity for the item.
   * 
   * @return
   */
  public float getYVelocity() {
    return yVelocity;
  }

  /**
   * Set the image bitmap for the item.
   * 
   * @param bitmap
   */
  public void setBitmap(Bitmap bitmap) {
    this.bitmap = bitmap;
  }

  /**
   * Return the image bitmap for the item.
   * 
   * @return
   */
  public Bitmap getBitmap() {
    return bitmap;
  }

  /**
   * Return the item image width.
   * 
   * @return The width in pixels
   */
  public int getWidth() {
    return width;
  }

  /**
   * Return the item image height.
   * 
   * @return The height in pixels
   */
  public int getHeight() {
    return height;
  }

  /**
   * Return the item type.
   * 
   * @return The type - 0 for larger paddle 1 for smaller paddle 2 for faster ball 3 for slower ball
   * 4 for harpoon 5 for faster shark 6 for slower shark.
   */
  public Integer getType() {
    return type;
  }

  /**
   * Set random type for this item.
   */
  public void setRandomType() {
    // Generates a random value and assigns it to this.type
    this.type = (int) (Math.random() * 8);
  }

  /**
   * Loop through all types.
   */
  public void changeType(long elapsedTime) {

    this.elapsedTime += elapsedTime;

    if (this.elapsedTime <= frameDuration) {
      return;
    }

    if (type < 9) {
      type++;
    }
    else {
      type = 0;
    }
    this.elapsedTime = 0;
  }

  /**
   * Return the x coordinate for the item.
   * 
   * @return The x coordinate
   */
  public float getX() {
    return x;
  }

  /**
   * Set the x coordinate for this item.
   * 
   * @param x coordinate
   */
  public void setX(float x) {
    this.x = x;
  }

  /**
   * Return the y coordinate for this item.
   * 
   * @return The y coordinate
   */
  public float getY() {
    return y;
  }

  /**
   * Set the y coordinate for this item.
   * 
   * @param y coordinate.
   */
  public void setY(float y) {
    this.y = y;
  }

  /**
   * Return the time remaining for the effect.
   * 
   * @return
   */
  public long getTimeRemaining() {
    return timeRemaining;
  }

  /**
   * Set the time remaining for the item effect.
   * 
   * @param timeRemaining Time is in milliseconds
   */
  public void setTimeRemaining(long timeRemaining) {
    this.timeRemaining = timeRemaining;
  }

  /**
   * Draw the item on the canvas.
   * 
   * @param canvas
   */
  public void draw(Canvas canvas) {
    // canvas.drawBitmap(bitmap, x, y, null);

    if (type == LARGER_PADDLE) {
      canvas.drawBitmap(MainGamePanel.paddleIncrease, x, y, null);
    }
    if (type == SMALLER_PADDLE) {
      canvas.drawBitmap(MainGamePanel.paddleDecrease, x, y, null);
    }
    if (type == SLOWER_BALL) {
      canvas.drawBitmap(MainGamePanel.greenClock, x, y, null);
    }
    if (type == FASTER_BALL) {
      canvas.drawBitmap(MainGamePanel.redClock, x, y, null);
    }
    if (type == SLOWER_SHARK) {
      canvas.drawBitmap(MainGamePanel.blueClock, x, y, null);
    }
    if (type == FASTER_SHARK) {
      canvas.drawBitmap(MainGamePanel.orangeClock, x, y, null);
    }
    if (type == HARPOON) {
      canvas.drawBitmap(MainGamePanel.harpoonItem, x, y, null);
    }
    if (type == SPIKED_BALL) {
      canvas.drawBitmap(MainGamePanel.spikedItem, x, y, null);
    }
    if (type == GHOST_BALL) {
      canvas.drawBitmap(MainGamePanel.ghostItem, x, y, null);
    }
    if (type == BOMB) {
      canvas.drawBitmap(MainGamePanel.bombItem, x, y, null);
    }
  }

  /**
   * Hide the item to somewhere outside the screen.
   */
  public void resetPosition() {
    visible = false;
    x = -50;
    y = -50;
    yVelocity = 0;
  }

  /**
   * Resets the item type.
   */
  public void resetType() {
    timeRemaining = -1;
    type = null;
  }

  /**
   * Update the item position.
   * 
   * @param viewHeight The height for the view passed in.
   * @param paddle The paddle.
   * @param ball The ball.
   * @param harpoon The harpoon.
   */
  public void update(Paddle paddle, Ball ball, Harpoon harpoon, Shark blueShark, Shark orangeShark,
      List<Fish> fishList, BlockEdges edges) {

    // if the item falling below the screen, reset it.
    if (y >= MainGamePanel.viewHeight) {
      resetPosition();
    }

    // set last updated time to current time if it's the first time
    // this method is called
    long currentTime = System.currentTimeMillis();
    if (lastUpdateTime < 0) {
      lastUpdateTime = currentTime;
      return;
    }

    // keep track of the elapsed time and last update time.
    long elapsedTime = currentTime - lastUpdateTime;
    lastUpdateTime = currentTime;

    if (visible) {
      changeType(elapsedTime);
    }

    // if there's still time left to use this item. update the time remaining
    if (timeRemaining > 0) {
      timeRemaining = timeRemaining - elapsedTime;
    }
    // if the time remaining is up, remove the power
    if (timeRemaining <= 0 && type != null && !visible) {
      removePower(paddle, ball, harpoon, blueShark, orangeShark, fishList, edges);
    }

    // update the y position
    y = y + yVelocity * elapsedTime / 1000 * pixelsPerMeter;
  }

  /**
   * Remove the power up / down effects.
   * 
   * @param paddle The paddle
   * @param ball The ball.
   * @param harpoon The harpoon.
   */
  public void removePower(Paddle paddle, Ball ball, Harpoon harpoon, Shark blueShark,
      Shark orangeShark, List<Fish> fishList, BlockEdges edges) {

    if (type == null) {
      return;
    }

    switch (type) {
    case LARGER_PADDLE:
      paddle.setBitmap(MainGamePanel.mediumPaddle);
      break;
    case SMALLER_PADDLE:
      paddle.setBitmap(MainGamePanel.mediumPaddle);
      break;
    case FASTER_BALL:
      ball.setPixelsPerMeter(10);
      break;
    case SLOWER_BALL:
      ball.setPixelsPerMeter(10);
      break;
    case HARPOON:
      if (!harpoon.getLaunched()) {
        harpoon.usedPowerup();
      }
      break;

    // let it continue to faster shark since they share the same code for restoring.
    case SLOWER_SHARK:
    case FASTER_SHARK:
      if (blueShark != null) {
        blueShark.setPixelsPerMeter(2.5f);
      }
      if (orangeShark != null) {
        orangeShark.setPixelsPerMeter(2.5f);
      }
      break;
    case SPIKED_BALL:
      ball.setBitmap(MainGamePanel.ballBitmap);
      ball.setSpiky(false);
      break;
    case GHOST_BALL:
      boolean ballNotInAnything = true;
      // whether the ball might be in the blocks
      if (!(edges.ballIsAboveHighestEdge(ball) || edges.ballIsBelowLowestEdge(ball)
          || edges.ballIsLeftToLeftmostEdge(ball) || edges.ballIsRightToRightmostEdge(ball))) {
        ballNotInAnything = false;
      }
      // whether the ball is in the sharks
      if (blueShark != null && ball.isInShark(blueShark)) {
        ballNotInAnything = false;
      }
      if (orangeShark != null && ball.isInShark(orangeShark)) {
        ballNotInAnything = false;
      }
      // whether the ball is in a fish.
      for (Fish fish : fishList) {
        if (ball.isInFish(fish)) {
          ballNotInAnything = false;
        }
      }

      if (ballNotInAnything) {
        ball.setBitmap(MainGamePanel.ballBitmap);
        ball.setGhost(false);
      }
      else {
        return;
      }
      break;
    case BOMB:
      break;
    default:
      break;
    }
    resetType();
  }

  /**
   * Make the item start falling anywhere from the top.
   * 
   */
  public void appear() {
    x = (int) (Math.random() * (MainGamePanel.viewWidth - width));
    y = -50;
    yVelocity = 10;
    setRandomType();
    visible = true;
  }

  /**
   * Handles the interaction between the player and the item by touch.
   * 
   * @param eventX The x coordinate of where the player touched.
   * @param eventY The y coordinate of where the player touched.
   * @param paddle The paddle.
   * @param ball The ball.
   * @param harpoon The harpoon.
   */
  public void handleActionDown(int eventX, int eventY, Paddle paddle, Ball ball, Harpoon harpoon,
      Shark blueShark, Shark orangeShark) {

    // if the event coordinate is within the item image.
    if (eventX >= x && eventX <= x + width) {
      if (eventY >= y && eventY <= y + height) {

        type = BOMB;

        // make paddle larger
        if (type == LARGER_PADDLE) {
          paddle.setBitmap(MainGamePanel.largePaddle);
        }

        // make paddle smaller
        else if (type == SMALLER_PADDLE) {
          paddle.setBitmap(MainGamePanel.smallPaddle);
        }

        // make the ball faster
        else if (type == FASTER_BALL) {
          ball.setPixelsPerMeter(12.5f);
        }
        // make the ball slower
        else if (type == SLOWER_BALL) {
          ball.setPixelsPerMeter(7.5f);
        }
        // obtained harpoon
        else if (type == HARPOON) {
          harpoon.obtainedPowerup();
        }
        // faster shark
        else if (type == FASTER_SHARK) {
          if (blueShark != null) {
            blueShark.setPixelsPerMeter(5);
          }
          if (orangeShark != null) {
            orangeShark.setPixelsPerMeter(5);
          }
        }
        // slower shark
        else if (type == SLOWER_SHARK) {
          if (blueShark != null) {
            blueShark.setPixelsPerMeter(1.25f);
          }
          if (orangeShark != null) {
            orangeShark.setPixelsPerMeter(1.25f);
          }
        }
        else if (type == SPIKED_BALL) {
          ball.setBitmap(MainGamePanel.spikedBallBitmap);
          ball.setSpiky(true);
        }
        else if (type == GHOST_BALL) {
          ball.setBitmap(MainGamePanel.ghostBallBitmap);
          ball.setGhost(true);
        }
        else if (type == BOMB) {
          if (blueShark != null) {
            blueShark.killed();
          }
          if (orangeShark != null) {
            orangeShark.killed();        	  
          }
        }
        // add 100 pts to score and set time remaining to 20 secs
        MainThread.addScore(100);
        timeRemaining = 20000;

        // reset this items position
        resetPosition();
      }
    }
  }

}
